{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "is_executing": false
    }
   },
   "outputs": [],
   "source": [
    "from gs_quant.session import Environment, GsSession\n",
    "from gs_quant.instrument import FXDoubleOneTouch\n",
    "from gs_quant.markets.portfolio import Portfolio\n",
    "from datetime import date\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "# external users should substitute their client id and secret; please skip this step if using internal jupyterhub\n",
    "GsSession.use(Environment.PROD, client_id=None, client_secret=None, scopes=('run_analytics',))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Basic Details"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "# get list of properties of an fx knockout - Note the knockout instrument will also do RKO (Reverse Knockout)\n",
    "FXDoubleOneTouch.properties()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "# in this example we will construct and price a portfolio of FX DNTs\n",
    "fx_dbl_touches = Portfolio()\n",
    "\n",
    "# you don't need to specify any parameters to get a valid trade.  All properties have defaults\n",
    "# Note that touch_or_no_touch defaults to \"No Touch\", so the default trade is a DNT not a DOT (see below cell)\n",
    "fx_dbl_touches.append(FXDoubleOneTouch())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Double **No** Touch vs Double **One** touch\n",
    "`touch_or_no_touch` controls whether the option pays if either barrier_level is breached (called a Double One Touch or DOT for short).  \n",
    "Or whether the option only pays if neither barrier_level has been breached by the `expiration_date` (called a Double No Touch or DNT)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from gs_quant.common import TouchNoTouch\n",
    "fx_dbl_touches.append(FXDoubleOneTouch(lower_barrier_level=.9, upper_barrier_level=1.2, touch_or_no_touch=TouchNoTouch.No_Touch))\n",
    "fx_dbl_touches.append(FXDoubleOneTouch(lower_barrier_level=.9, upper_barrier_level=1.2, touch_or_no_touch=TouchNoTouch.Touch))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Buying vs Selling"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "# buy_sell indicates whether the option is bought (long) or sold (short) \n",
    "# It can be represented by the BuySell enum or a string \n",
    "fx_dbl_touches.append(FXDoubleOneTouch(buy_sell='Buy'))\n",
    "\n",
    "from gs_quant.common import BuySell\n",
    "fx_dbl_touches.append(FXDoubleOneTouch(buy_sell=BuySell.Sell))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Currencies involved\n",
    "`pair` is the `FXDoubleOneTouch`'s underlying currency pair. It is a string of two ccy iso codes, optionally separated with a space (' ').  \n",
    "The first currency is the base (transaction) currency and the second is the quote currency.\n",
    "The upper and lower barrier levels are then levels corresponding to this FX rate\n",
    "The option also has a `notional_currency` and `notional_amount` field, this corresponds to the conditional option payout."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "from gs_quant.common import Currency\n",
    "# In this case, base currency is 'EUR' and quote currency is 'USD'\n",
    "# This option gives the purchasor a 100k EUR payout if the barrier levels are not breached\n",
    "fx_dbl_touches.append(FXDoubleOneTouch(buy_sell=BuySell.Buy, pair='EUR USD', notional_currency=Currency.EUR, notional_amount=100e3))\n",
    "\n",
    "# Here, base currency is 'GBP' and quote currency is 'USD'\n",
    "# This option gives the purchasor a 100k USD payout if either barrier is breached\n",
    "fx_dbl_touches.append(FXDoubleOneTouch(buy_sell=BuySell.Buy, touch_or_no_touch=\"Touch\", pair='GBPUSD', notional_currency=Currency.EUR, notional_amount=\"100k\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Barrier Levels\n",
    "`upper_barrier_level` and `lower_barrier_level` are the exchange rates stuck for the DOT/DNT's underlying currency pair, which can be specified by a double \n",
    "or a string with a keyword/letter. If a string is used, it represents a relative value. When the trade is resolved, we solve for the strike_price \n",
    "\n",
    "The specific solver keys are: \n",
    "* 'S'    - current spot rate\n",
    "* 'F'    - forward\n",
    "* 'D'    - Delta Strikes of a vanilla option\n",
    "* 'P'    - Premium\n",
    "\n",
    "You can use these keys with the following formats: \n",
    "* For S, F, ATM, ATMF: 's*1.05', 'F+10%', '1.05*ATMF+.01'\n",
    "* For Delta Strikes, specify the option delta: '25D', '20D-.01', etc.\n",
    "* You can also solve for Premium: P=<target premium>, P=<target premium> P=,<target>%, PPct=<target>\n",
    "\n",
    "To have the upper barrier 2% above the current spot either of the following syntaxs would be valid:  \n",
    "`upper_barrier_level=\"s+2%\"` or `upper_barrier_level=\"s*1.02\"`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "# Here the option is set to have fixed barrier levels \n",
    "fx_dbl_touches.append(FXDoubleOneTouch(pair='EURGBP', expiration_date=\"1m\", lower_barrier_level=0.8, upper_barrier_level=0.95))\n",
    "\n",
    "# The option is sold have the lower barrier 1% below spot and upper barrier 1% above the fwd\n",
    "fx_dbl_touches.append(FXDoubleOneTouch(pair='EURGBP', expiration_date=\"1m\", lower_barrier_level=\"s-1%\", upper_barrier_level=\"f+1%\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Option Premium\n",
    "`premium_currency` is the premium amount's denominated currency.  \n",
    "It can be a Currency enum or a string. By default, `premium_currency` will match the `notional_currency`.  \n",
    "The `premium` will **default to the fair premium** s.t. that the PresentValue of the option + premium = 0.  \n",
    "You therefore may find it helpful to set the premium explictly to 0 s.t. the PresentValue of the DOT/DNT is just the value of the option.  \n",
    "`premium_payment_date` is the date the premium is exchanged. It can either be a date or string such as \"fwd\" or \"spot\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "# In this case, the payout and premium currency of the EURGBP DNt will be EUR\n",
    "fx_dbl_touches.append(FXDoubleOneTouch(pair='EUR GBP', notional_currency='EUR', premium_currency='EUR'))\n",
    "\n",
    "# Here we explictly set the premium to 0 so measures like DollarPrice or PresentValue only include the option value\n",
    "fx_dbl_touches.append(FXDoubleOneTouch(pair='EUR GBP', premium=0, notional_currency='EUR'))\n",
    "\n",
    "# Here we set it the option to have forward premium by setting `premium_payment_date` to 'fwd' or 'forward'\n",
    "fx_dbl_touches.append(FXDoubleOneTouch(pair='EUR GBP', premium_payment_date='fwd'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Premium Solving\n",
    "It is possible to solve for the level of a single barrier to reach a certain Premium (in % or absolute value)  \n",
    "You can also sovle both barrier levels for a target premium in which case they will be symmetrical spaced from current spot.  \n",
    "Common syntax for solving for permium in % or absolute level include `p=10%` and `p=-200k`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import gs_quant.risk as risk\n",
    "# e.g. Solve X in a \"1m USDJPY spot-3%/X DNT\" s.t. that the fair premium is 10% of the notional\n",
    "upper_solve = FXDoubleOneTouch(pair='USD JPY', expiration_date='1m', lower_barrier_level='spot-3%', upper_barrier_level=\"p=10%\")\n",
    "calced = upper_solve.calc((risk.FairPremium, risk.ResolvedInstrumentValues))\n",
    "print(calced[risk.FairPremium], calced[risk.ResolvedInstrumentValues].upper_barrier_level)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# e.g. Solve for a 1m USDJPY DNT with symmetric strikes aorund spot s.t. the premium is 5%\n",
    "double_solve = FXDoubleOneTouch(pair='USD JPY', expiration_date='1m', lower_barrier_level='p=5%', upper_barrier_level='p=5%', premium=0)\n",
    "calced = double_solve.calc((risk.FairPremiumInPercent, risk.FXSpot, risk.ResolvedInstrumentValues))\n",
    "resolved = calced[risk.ResolvedInstrumentValues]\n",
    "print(calced[risk.FairPremiumInPercent]*100, resolved.lower_barrier_level, calced[risk.FXSpot], resolved.upper_barrier_level)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "pd.DataFrame(fx_dbl_touches.price())"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.4"
  },
  "pycharm": {
   "stem_cell": {
    "cell_type": "raw",
    "metadata": {
     "collapsed": false
    },
    "source": []
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
